#pragma once

#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"

const int defaultfd = -1;
const std::string defaultip = "0.0.0.0";
const int backlog = 10;

extern Log lg;

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    listenError
};

class TcpServer;

struct ThreadData
{
public:
    ThreadData(int sockfd, const std::string& client_ip, const u_int16_t& client_port, TcpServer* tcpserver)
        : sockfd_(sockfd), client_ip_(client_ip), client_port_(client_port), tcpserver_(tcpserver)
    {}
public:
    int sockfd_;
    std::string client_ip_;
    u_int16_t client_port_;
    TcpServer* tcpserver_;
};

class TcpServer
{
public:
    TcpServer(const u_int16_t& port, const std::string ip = defaultip): listensockfd_(defaultfd), port_(port), ip_(ip)
    {}

    void InitServer()
    {
        // 1. 创建socket
        listensockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if(listensockfd_ < 0)
        {
            lg(Fatal, "create socket error: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, "create socket success, sockfd: %d", listensockfd_);

        int opt = 1;
        setsockopt(listensockfd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); // 设置端口复用

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &local.sin_addr);    // 将点分十进制的ip地址转换为网络字节序的ip地址
        // local.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0  表示任意地址

        // 2. 绑定socket
        if(bind(listensockfd_, (struct sockaddr*)&local, sizeof(local)) < 0)
        {   
            lg(Fatal, "bind error: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind socket success, sockfd: %d", listensockfd_);

        // Tcp是面向连接的，服务器一般是比较被动的，服务器一直处于等待连接的状态——监听状态
        // 3. 监听socket
        if(listen(listensockfd_, backlog) < 0)
        {
            lg(Fatal, "listen error: %d, errstring: %s", errno, strerror(errno));
            exit(listenError);
        }
        lg(Info, "listen socket success, sockfd: %d", listensockfd_);
    }

    // static void* Routine(void* args)
    // {
    //     pthread_detach(pthread_self()); // 线程分离
    //     ThreadData* td = static_cast<ThreadData*>(args);
    //     td->tcpserver_->Service(td->sockfd_, td->client_ip_, td->client_port_);
    //     close(td->sockfd_);
    //     delete td;
    //     return nullptr;
    // }

    void Start()
    {
        // 守护进程
        Daemon();
        // 忽略子进程退出信号，防止僵尸进程
        signal(SIGCHLD, SIG_IGN);   
        // 初始化线程池
        ThreadPool<Task>::GetInstance()->Start();

        lg(Info, "tcp server start, wait client connect...");
        // 4. 等待客户端连接
        while(true)
        {
            // a. 获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensockfd_, (struct sockaddr*)&client, &len);
            if(sockfd < 0)
            {
                lg(Warning, "accept error: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            u_int16_t client_port = ntohs(client.sin_port);
            char client_ip[32];
            inet_ntop(AF_INET, &client.sin_addr, client_ip, sizeof(client_ip));

            // b. 根据新连接来通信
            lg(Info, "get a new link..., sockfd: %d, client_ip: %s, client_port: %d", sockfd, client_ip, client_port);

            // versio1————单进程
            // Service(sockfd, client_ip, client_port);
            // close(sockfd);

            // version2————多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     // 子进程
            //     close(listensockfd_);
            //     if(fork() > 0)
            //     {
            //         // 子进程退出
            //         exit(0);
            //     }
            //     // 孙子进程继续提供服务，子进程退出，孙子进程成为孤儿进程，由系统(init进程)收养
            //     Service(sockfd, client_ip, client_port);
            //     close(sockfd);
            //     exit(0);
            // }
            // else if(id > 0)
            // {
            //     // 父进程
            //     close(sockfd);
            //     pid_t wpid = waitpid(id, nullptr, 0); 
            // }
            // else
            // {
            //     // fork失败
            //     close(sockfd);
            //     lg(Warning, "fork error: %d, errstring: %s", errno, strerror(errno));     
            // }

            // version3————多线程
            // ThreadData* td = new ThreadData(sockfd, client_ip, client_port, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);

            // version4————线程池
            Task t(sockfd, client_ip, client_port);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }

    ~TcpServer(){}

private:
    int listensockfd_;
    u_int16_t port_;
    std::string ip_;
};
